package com.zero.business.order.listener;


import com.zero.business.order.service.OrderService;
import com.zero.common.exception.ServiceException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

/*
*   监听 rocketmq 中的消息
* */
@Component
@RocketMQMessageListener(
        topic = "orderTopic",                     // 主题
        consumerGroup = "order-consumer-group8",   // 消费者组
        // 设置消费者的线程数  (IO密集型：2n)
        consumeThreadNumber = 16*2,
        consumeMode = ConsumeMode.CONCURRENTLY    // 并发模式
)
public class OrderListener implements RocketMQListener<MessageExt> {

    // 获取操作 redis 的对象    这里redis的参数名称必须是：stringRedisTemplate，不能是redisTemplate，否则会报异常，就他妈离谱
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private OrderService orderService;

    @Resource
    private HttpServletResponse response;

    /*
    *   监听 orderTopic 主题中的消息                     有点杀鸡用牛刀的感觉
    *      利用 redis setnx 的特性，实现线程安全
    * */
    @Override
    public void onMessage(MessageExt messageExt) {
        // 获取消息体
        String body = new String(messageExt.getBody());
        String[] ids = body.split("-");
//        // 获取会员ID
        int userId = Integer.parseInt(ids[0]);
        // 获取车辆ID
        int bicycleId = Integer.parseInt(ids[1]);

        // 如果多个线程走到这里，他们的 bicycleId 相同，但是只能有一个线程在 redis 中 设置 key 为 lock:bicycleId 的数据，相当于这个线程拿到了锁
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock:" + bicycleId, "");

        if (flag) { // 拿到锁
            // 执行业务逻辑
            orderService.useBicycle(userId, bicycleId);
        } else { // 没有拿到锁
            // 将未拿到锁的线程，打印在控制台
            System.out.println(Thread.currentThread().getName() + "-->不好意思，该车已经有人使用了");
            // 直接返回响应
//            ResponseJsonUtil.responseToFront(CodeConstants.BICYCLE_USING, "不好意思，该车辆已经有人使用了，请选择其他车辆",response);
            throw new ServiceException(200, "不好意思，该车辆已经有人使用了，请选择其他车辆");
        }


    }
}
